#include "SceneManager.h"
//#include "World.h"
#include "WorldEntity.h"

CSceneManager::CSceneManager(void){}

CSceneManager::~CSceneManager(void)
{
	if(m_rootQuadTree.m_NE!=0)
		deleteTree(m_rootQuadTree.m_NE, m_depth);
	delete m_rootQuadTree.m_NE;

	if(m_rootQuadTree.m_SE!=0)
		deleteTree(m_rootQuadTree.m_SE, m_depth);
	delete m_rootQuadTree.m_SE;

	if(m_rootQuadTree.m_NW!=0)
		deleteTree(m_rootQuadTree.m_NW, m_depth);
	delete m_rootQuadTree.m_NW;

	if(m_rootQuadTree.m_SW!=0)
		deleteTree(m_rootQuadTree.m_SW, m_depth);
	delete m_rootQuadTree.m_SW;
}

bool CSceneManager::initialiseQuadTree(int depth)
{
	//set the depth
	m_depth = depth;

	//create the tree with blank data
	createTree(&m_rootQuadTree, depth);

	//set the boundaries of each nodes
	setWorldBoundaries(&m_rootQuadTree, 0, 0, 3300, 1000, m_depth);

	return true;
}

//return a pointer to an array of entities
vector<CWorldEntity*>* CSceneManager::getVectorOfArea(CWorldEntity* entity, int indexLeaf)
{
	//calculate the four points around the entity
	int minX = entity->getPosition().m_x;
	int maxX = minX + entity->getCollisionRectangle().m_right;
	int minY = entity->getPosition().m_y;
	int maxY = minY + entity->getCollisionRectangle().m_bottom;
	
	//create a vector that store the vectors of entities
	vector<vector<CWorldEntity*>*> pntVector;

	//get the vectors
	getVector(minX, maxX, minY, maxY, &m_rootQuadTree, pntVector);
	
	//if the index is in the vector
	if((unsigned int)indexLeaf<pntVector.size())
		return pntVector[indexLeaf];
	else //if the index is out of the vector
		return 0;
}

void CSceneManager::updateEntity(CWorldEntity* entity)
{
	//delete the pointers to that entities
	deleteEntity(entity);

	//add the entity
	putEntity(entity);
}

void CSceneManager::scrollBoundaries(const CVector2i& v)
{
	scroll(v, &m_rootQuadTree, m_depth);
}

void CSceneManager::addEntity(CWorldEntity* entity)
{
	//calculate the four points around the entity
	int minX = entity->getPosition().m_x;
	int maxX = minX + entity->getCollisionRectangle().m_right;
	int minY = entity->getPosition().m_y;
	int maxY = minY + entity->getCollisionRectangle().m_bottom;

	//get the array of entity where the entity gotta be
	vector<vector<CWorldEntity*>*> pntArray;
	getVector(minX, maxX, minY, maxY, &m_rootQuadTree, pntArray);

	for(vector<vector<CWorldEntity*>*>::iterator i=pntArray.begin(); i!=pntArray.end(); i++)
		(*i)->push_back(entity);
}

bool CSceneManager::createTree(CNode* node, int depth)
{
	//if the depth is null we return
	if(depth<=0)	
		return true;
	

	//creation of the next level
	if(depth == 1)
	{
		node->m_NE = new CLeaf();
		node->m_NW = new CLeaf();
		node->m_SE = new CLeaf();
		node->m_SW = new CLeaf();

		m_arrayOfLeaves.push_back((CLeaf*)node->m_NE);
		m_arrayOfLeaves.push_back((CLeaf*)node->m_NW);
		m_arrayOfLeaves.push_back((CLeaf*)node->m_SE);
		m_arrayOfLeaves.push_back((CLeaf*)node->m_SW);

	}
	else
	{
		node->m_NE = new CNode();
		node->m_NW = new CNode();
		node->m_SE = new CNode();
		node->m_SW = new CNode();
	}

	//recursive call with depth-1
	createTree(node->m_NE, depth-1);
	createTree(node->m_SE, depth-1);
	createTree(node->m_NW, depth-1);
	createTree(node->m_SW, depth-1);
	return true;

}

void CSceneManager::setWorldBoundaries(CNode* node, int minX, int minY, int maxX, int maxY, int depth)
{
	//set the boundaries
	node->m_minX = minX;
	node->m_minY = minY;
	node->m_maxX = maxX;
	node->m_maxY = maxY;

	//if it's the final level
	if(depth==0)
	{
		m_width = node->m_maxX - node->m_minX;
		m_height = node->m_maxY - node->m_minY;
		return;
	}
	
	//calculate the boundaries of the next level
	int middleX = (minX + maxX)/2;
	int middleY = (minY + maxY)/2;

	//recursive call with depth-1
	setWorldBoundaries(node->m_NE, middleX, minY, maxX, middleY, depth-1);
	setWorldBoundaries(node->m_NW, minX, minY, middleX-1, middleY, depth-1);
	setWorldBoundaries(node->m_SE, middleX, middleY+1, maxX, maxY, depth-1);
	setWorldBoundaries(node->m_SW, minX, middleY+1, middleX-1, maxY, depth-1);
}

CLeaf* CSceneManager::getLeafNode(const CVector2i& v, CNode* node, int depth)
{
	//if we get to the leaf node
	if(depth == 0)
		return (CLeaf*)node;

	if(v.m_y>=node->m_SE->m_minY && v.m_x >= node->m_NE->m_minX)//north east
		return getLeafNode(v, node->m_NE, depth-1);
	else if(v.m_y>=node->m_SE->m_minY && !(v.m_x >= node->m_NE->m_minX)) //north west
		return getLeafNode(v, node->m_NW, depth-1);
	else if(!(v.m_y>=node->m_SE->m_minY) && v.m_x >= node->m_NE->m_minX) //south east
		return getLeafNode(v, node->m_SE, depth-1);
	else //south west
		return getLeafNode(v, node->m_SW, depth-1);

}

void CSceneManager::deleteEntity(CWorldEntity* entity)
{
	vector<vector<CWorldEntity*>*> pntArray;

	int minX = entity->getPosition().m_x;
	int minY = entity->getPosition().m_y;
	int maxX = minX + entity->getCollisionRectangle().m_right;
	int maxY = minY + entity->getCollisionRectangle().m_bottom;

	getVector(minX, maxX, minY, maxY, &m_rootQuadTree, pntArray);

	for(vector<vector<CWorldEntity*>*>::iterator iteratorArray=pntArray.begin(); iteratorArray!=pntArray.end(); iteratorArray++)
	{
		bool found = false;
		
		vector<CWorldEntity*>::iterator iteratorEntity = (*iteratorArray)->begin();
		vector<CWorldEntity*>::iterator iteratorLastEntity = (*iteratorArray)->end();

		while(!found && iteratorEntity!=iteratorLastEntity)
		{
			if((*iteratorEntity)==entity)
			{
				(*iteratorArray)->erase(iteratorEntity);
				found=true;
			}
			else
				iteratorEntity++;
		}
	}
}

void CSceneManager::putEntity(CWorldEntity* entity)
{
	//calculate the four points around the entity
	int minX = entity->getPosition().m_x;
	int maxX = minX + entity->getCollisionRectangle().m_right;
	int minY = entity->getPosition().m_y;
	int maxY = minY + entity->getCollisionRectangle().m_bottom;

	//get the array of entity where the entity gotta be
	vector<vector<CWorldEntity*>*> pntArray;
	getVector(minX, maxX, minY, maxY, &m_rootQuadTree, pntArray);

	for(vector<vector<CWorldEntity*>*>::iterator i=pntArray.begin(); i!=pntArray.end(); i++)
		(*i)->push_back(entity);
}

void CSceneManager::scroll(const CVector2i& v, CNode* node, int depth)
{
	if(depth<0)
		return;

	node->m_maxX+=v.m_x;
	node->m_maxY+=v.m_y;
	node->m_minX+=v.m_x;
	node->m_minY+=v.m_y;

	int newDepth = depth -1;

	scroll(v, node->m_NE, newDepth);
	scroll(v, node->m_NW, newDepth);
	scroll(v, node->m_SE, newDepth);
	scroll(v, node->m_SW, newDepth);
}

void CSceneManager::deleteTree(CNode* node, int depth)
{
	const int endDepth = 2;
	if(depth == endDepth)
	{
		CLeaf* leaf = (CLeaf*)(node->m_NE);
		delete leaf;
		node->m_NE = 0;

		leaf = (CLeaf*)(node->m_NW);
		delete leaf;
		node->m_NW = 0;

		leaf = (CLeaf*)(node->m_SE);
		delete leaf;
		node->m_SE = 0;

		leaf = (CLeaf*)(node->m_SW);
		delete leaf;
		node->m_SW = 0;
		return;
	}

	int newDepth = depth-1;
	deleteTree(node->m_NE, newDepth);
	deleteTree(node->m_NW, newDepth);
	deleteTree(node->m_SE, newDepth);
	deleteTree(node->m_SW, newDepth);

	delete node->m_NE;
	node->m_NE = 0;
	delete node->m_NW;
	node->m_NW = 0;
	delete node->m_SE;
	node->m_SE = 0;
	delete node->m_SW;
	node->m_SW = 0;
}

void CSceneManager::getVector(int minX, int maxX, int minY, int maxY, CNode* node, vector<vector<CWorldEntity*>*>& pntVector)
{
	//if it's a leaf
	if(node->m_SW == 0)
	{
		pntVector.push_back(&((CLeaf*)node)->m_vectorOfEntity);
		return;
	}

	//if the next is north east
	int minXNode = node->m_NE->m_minX;
	int maxXNode = node->m_NE->m_maxX;
	int minYNode = node->m_NE->m_minY;
	int maxYNode = node->m_NE->m_maxY;

	if(minX <= maxXNode && maxX >= minXNode && minY<=maxYNode && maxY >= minYNode)
		getVector(minX, maxX, minY, maxY, node->m_NE, pntVector);

	//if it's north west
	minXNode = node->m_NW->m_minX;
	maxXNode = node->m_NW->m_maxX;
	minYNode = node->m_NW->m_minY;
	maxYNode = node->m_NW->m_maxY;

	if(minX <= maxXNode && maxX >= minXNode && minY<=maxYNode && maxY >= minYNode)
		getVector(minX, maxX, minY, maxY, node->m_NW, pntVector);

	//if it's south east
	minXNode = node->m_SE->m_minX;
	maxXNode = node->m_SE->m_maxX;
	minYNode = node->m_SE->m_minY;
	maxYNode = node->m_SE->m_maxY;

	if(minX <= maxXNode && maxX >= minXNode && minY<=maxYNode && maxY >= minYNode)
		getVector(minX, maxX, minY, maxY, node->m_SE, pntVector);

	//if it's south west
	minXNode = node->m_SW->m_minX;
	maxXNode = node->m_SW->m_maxX;
	minYNode = node->m_SW->m_minY;
	maxYNode = node->m_SW->m_maxY;

	if(minX <= maxXNode && maxX >= minXNode && minY<=maxYNode && maxY >= minYNode)
		getVector(minX, maxX, minY, maxY, node->m_SW, pntVector);


}
